home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cocktail
/
ell.lha
/
ell
/
src
/
Sem.estra
< prev
next >
Wrap
Text File
|
1992-08-18
|
19KB
|
892 lines
(*
* ell2 - a redesign of ell
*
* $RCSfile: Sem.estra,v $
*
* purpose: semantic analysis
*
* $Author: grosch $
* $Date: 1992/08/07 15:32:36 $
*)
TRANSFORMATION Semantics
GLOBAL {
FROM ArgCheck IMPORT tLanguage, LANGUAGE;
FROM Codes IMPORT IsCoded, IsCode, SetCode, SetDefCode, EmptyRecSetIndex,
cNoIndex, SetIndex, RecSetIndex;
FROM Derivable IMPORT TestDerivable, IsDerivable;
FROM Errors IMPORT eError, eWarning, eIdent, eIdentSet, eInteger,
InError, ErrorMessage, ErrorMessageI, ERROR;
FROM Positions IMPORT NoPosition, tPosition;
FROM First IMPORT Firsts, IsLeftRec;
FROM Follow IMPORT Follows;
FROM Idents IMPORT tIdent, MaxIdent, WriteIdent;
FROM Reachable IMPORT WindThrough, IsReachable;
FROM Scanner IMPORT NoIdent, NoValue, EndOfToken, Epsilon;
FROM Sets IMPORT tSet, MakeSet, ReleaseSet, IsEmpty, IsSubset, IsEqual,
IsElement, Assign, Union, Difference, Include,
Exclude, AssignEmpty, Intersection, Card;
FROM SYSTEM IMPORT ADR;
FROM Table IMPORT InitTable, SetExpr, SetLeaf;
FROM Tree IMPORT tTree, NoTree;
FROM Types IMPORT BeginTypes, MakeTerm, MakeNonterm, IsDeclared,
Terminals, IsTerm, IsNonterm;
CONST
eAlreadyDeclared = 40;
eNotDeclared = 41;
eCodeExist = 42;
eNoRules = 43;
eNotReachable = 44;
eNotDerivable = 45;
eEnter = 46; (* eEnterWith = 47 *)
eByPass = 48; (* eByPassWith = 49 *)
eLeave = 50; (* eLeaveWith = 51 *)
eLeftRec = 52;
VAR
LeftSide: tIdent;
EmptySet, EpsilonSet: tSet;
PROCEDURE IdentError (error, class: INTEGER; pos: tPosition; ident: tIdent);
BEGIN
IF ident # NoIdent THEN
ErrorMessageI (error, class, pos, eIdent, ADR (ident));
END;
END IdentError;
PROCEDURE IntError (error, class: INTEGER; pos: tPosition; int: INTEGER);
BEGIN
ErrorMessageI (error, class, pos, eInteger, ADR (int));
END IntError;
PROCEDURE Check (VAR I: tSet; E: tSet; code: INTEGER; pos: tPosition);
BEGIN
IF IsSubset (I, E) THEN
ErrorMessage (code, eError, pos);
ELSE
Intersection (I, E);
IF NOT IsEmpty (I) THEN
ErrorMessageI (code+1, eWarning, pos, eIdentSet, ADR (I));
END;
END;
END Check;
CONST
MinSetSizeC = 2;
MinCasesC = 3;
MinSetSizeM2 = 2;
MinCasesM2 = 3;
VAR
MinSetSize: CARDINAL;
MaxDepth: INTEGER;
AnySymbol: tSet;
PROCEDURE Index (set: tSet): INTEGER;
BEGIN
Exclude (set, Epsilon);
IF Card (set) < MinSetSize THEN
RETURN cNoIndex;
ELSE
RETURN SetIndex (set);
END;
END Index;
PROCEDURE ExpIndex (first, follow, recovery: tSet): INTEGER;
VAR LocalFollow: tSet;
VAR result: INTEGER;
BEGIN
MakeSet (LocalFollow, MaxIdent ());
Assign (LocalFollow, follow);
Intersection (LocalFollow, recovery);
Union (LocalFollow, first);
Exclude (LocalFollow, Epsilon);
result := RecSetIndex (LocalFollow);
ReleaseSet (LocalFollow);
RETURN result;
END ExpIndex;
PROCEDURE SetMinSetSize;
BEGIN
CASE LANGUAGE OF
| C:
MinSetSize := MinSetSizeC;
MaxDepth := MinCasesC - 2;
| MODULA2:
MinSetSize := MinSetSizeM2;
MaxDepth := MinCasesM2 - 2;
END;
END SetMinSetSize;
}
GRAMMAR Tree
grammar =
| Grammar (sections, tokens, rules)
sections =
| Sections0 ()
| Sections (section, sections)
section =
| Export (codes)
| Global (codes)
| Local (codes)
| Begin (codes)
| Close (codes)
codes =
| Codes0 ()
| Codes (code, codes)
code =
| Code ()
tokens =
| Tokens0 ()
| Tokens (token, tokens)
token =
| Token (id, number)
id =
| Id ()
number =
| Number ()
rules =
| Rules0 ()
| Rules (rule, rules)
rule =
| Rule (id, codes, expr)
expr =
| Option (expr)
| Times (expr)
| Plus (expr)
| List (body: expr, sep: expr)
| Action (codes)
| Leaf (id)
expr ->
alternative =
| Alternative0 ()
| Alternative (expr, alternative)
expr ->
sequence =
| Sequence0 ()
| Sequence (expr, sequence)
FUNCTION Analyse / grammar, rules /
/*
* semantic analysis
*/
Grammar (sections, tokens, rules)
{
BeginTypes;
MakeTerm (Epsilon);
MakeTerm (EndOfToken);
SetCode (EndOfToken, 0);
Declare (tokens);
Declare (rules);
InitTable;
Declared (tokens);
Declared (rules);
Reduced (Grammar);
Analyse (rules);
}
Rules0 ()
{
ErrorMessage (eNoRules, eError, NoPosition);
}
Rules (Rule (Id (), codes, expr), rules)
DECLARE { VAR
RecIn, RecOut, Empty: tSet;
IsCalling: BOOLEAN;
} {
Firsts;
Follows (Id.ident);
IF InError THEN RETURN END;
MakeSet (EmptySet , MaxIdent ());
MakeSet (EpsilonSet , MaxIdent ());
Include (EpsilonSet, Epsilon);
LL1 (Rules, EmptySet);
ReleaseSet (EmptySet);
ReleaseSet (EpsilonSet);
MakeSet (RecIn, MaxIdent ());
MakeSet (RecOut, MaxIdent ());
Recovery (Rules, RecIn, RecOut);
ReleaseSet (RecIn);
ReleaseSet (RecOut);
SetMinSetSize;
MakeSet (AnySymbol, MaxIdent ());
Terminals (AnySymbol);
Include (AnySymbol, EndOfToken);
MakeSet (Empty, MaxIdent ());
EmptyRecSetIndex := RecSetIndex (Empty);
PrepareCode (Rules, AnySymbol, IsCalling);
ReleaseSet (AnySymbol);
ReleaseSet (Empty);
}
FUNCTION Declare / tokens, token, rules /
/*
* declare terminals
* set codes
*/
Tokens0 () {}
Tokens (token, tokens)
{
Declare (token);
Declare (tokens);
}
Token (Id (), Number ())
{
IF IsDeclared (Id.ident) THEN
IdentError (eAlreadyDeclared, eError, Id.pos, Id.ident);
Id.ident := NoIdent;
ELSIF Id.ident # NoIdent THEN
MakeTerm (Id.ident);
IF Number.value # NoValue THEN
IF IsCode (Number.value) THEN
IntError (eCodeExist, eError, Number.pos, Number.value);
ELSE
SetCode (Id.ident, Number.value);
END;
END;
END;
}
/*
* declare nonterminals
*/
Rules0 () {}
Rules (Rule (Id (), codes, expr), rules)
{
IF IsDeclared (Id.ident) THEN
IdentError (eAlreadyDeclared, eError, Id.pos, Id.ident);
Id.ident := NoIdent;
ELSE
MakeNonterm (Id.ident);
END;
Declare (rules);
}
FUNCTION Declared / tokens, token, rules, expr /
/*
* set default codes for uncoded terminals
*/
Tokens0 () {}
Tokens (token, tokens)
{
Declared (token);
Declared (tokens);
}
Token (Id (), Number ())
{
IF (Id.ident # NoIdent) & (NOT IsCoded (Id.ident)) THEN
SetDefCode (Id.ident);
END;
}
/*
* are all leafs declared
* set expession of nonterminals
* collect leafs of nonterminals
*/
Rules0 ()
{}
Rules (Rule (Id (), codes, expr), rules)
{
LeftSide := Id.ident;
SetExpr (LeftSide, expr);
Declared (expr);
Declared (rules);
}
Option (expr)
{
Declared (expr);
}
Times (expr)
{
Declared (expr);
}
Plus (expr)
{
Declared (expr);
}
List (body: expr, sep: expr)
{
Declared (body);
Declared (sep);
}
Action (codes) {}
Leaf (Id ())
{
IF NOT IsDeclared (Id.ident) THEN
IdentError (eNotDeclared, eError, Id.pos, Id.ident);
ELSE
SetLeaf (LeftSide, Id.ident);
END;
}
Alternative0 () {}
Alternative (expr, alternative)
{
Declared (expr);
Declared (alternative);
}
Sequence0 () {}
Sequence (expr, sequence)
{
Declared (expr);
Declared (sequence);
}
FUNCTION Reduced / grammar, rules, tokens, token /
/*
* is the grammar reduced ? - report errors
*/
Grammar (sections, tokens, Rules0 ())
{
}
Grammar (sections, tokens, Rules (Rule (Id (), codes, expr), rules))
{
WindThrough (Id.ident);
TestDerivable;
Reduced (tokens);
Reduced (Rules);
}
Tokens0 () {}
Tokens (token, tokens)
{
Reduced (token);
Reduced (tokens);
}
Token (Id (), Number ())
{
IF NOT IsReachable (Id.ident) THEN
IdentError (eNotReachable, eWarning, Id.pos, Id.ident);
END;
}
Rules0 ()
{
}
Rules (Rule (Id (), codes, expr), rules)
{
IF NOT IsReachable (Id.ident) THEN
IdentError (eNotReachable, eError, Id.pos, Id.ident);
END;
IF NOT IsDerivable (Id.ident) THEN
IdentError (eNotDerivable, eError, Id.pos, Id.ident);
END;
Reduced (rules);
}
FUNCTION LL1 Exclude: tSet -> / rules, expr /
/*
* is the grammar ll1 ? - report errors and repair
*/
Rules0 ()
{}
Rules (Rule (Id (), codes, expr), rules)
{
IF IsLeftRec (Id.ident) THEN
IdentError (eLeftRec, eError, Id.pos, Id.ident);
END;
LL1 (expr, Exclude);
LL1 (rules, Exclude);
}
Option (expr)
DECLARE {
VAR In, ByPass, Set: tSet;
} {
MakeSet (In, MaxIdent ());
MakeSet (ByPass, MaxIdent ());
MakeSet (Set, MaxIdent ());
Assign (In, expr.fifo);
Assign (ByPass, expr.follow);
Assign (Set, expr.fifo); Union (Set, Exclude);
Check (ByPass, Set, eByPass, Option.pos);
Check (In, Exclude, eEnter, Option.pos);
ReleaseSet (In);
ReleaseSet (ByPass);
ReleaseSet (Set);
LL1 (expr, Exclude);
Difference (Option.fifo, Exclude);
}
Times (expr)
DECLARE {
VAR In, Leave, Set: tSet;
} {
MakeSet (In, MaxIdent ());
MakeSet (Leave, MaxIdent ());
MakeSet (Set, MaxIdent ());
Assign (In, expr.fifo);
Assign (Leave, Times.follow);
Assign (Set, expr.fifo); Union (Set, Exclude);
Check (Leave, Set, eLeave, Times.pos);
Check (In, Exclude, eEnter, Times.pos);
ReleaseSet (In);
ReleaseSet (Leave);
ReleaseSet (Set);
LL1 (expr, EmptySet);
Difference (Times.fifo, Exclude);
}
Plus (expr)
DECLARE {
VAR In, Leave: tSet;
} {
MakeSet (In, MaxIdent ());
MakeSet (Leave, MaxIdent ());
Assign (In, Plus.fifo);
Assign (Leave, Plus.follow);
Check (Leave, In, eLeave, Plus.pos);
Check (In, Exclude, eEnter, Plus.pos);
ReleaseSet (In);
ReleaseSet (Leave);
LL1 (expr, EmptySet);
Difference (Plus.fifo, Exclude);
}
List (body: expr, sep: expr)
DECLARE {
VAR In, Keep, Leave: tSet;
} {
MakeSet (In, MaxIdent ());
MakeSet (Keep, MaxIdent ());
MakeSet (Leave, MaxIdent ());
Assign (In, List.fifo);
Assign (Keep, sep.fifo);
Assign (Leave, List.follow);
Check (Leave, Keep, eLeave, List.pos);
Check (In, Exclude, eEnter, List.pos);
ReleaseSet (In);
ReleaseSet (Keep);
ReleaseSet (Leave);
LL1 (body, EmptySet);
LL1 (sep, EmptySet);
Difference (List.fifo, Exclude);
}
Action (codes)
DECLARE {
VAR In: tSet;
} {
MakeSet (In, MaxIdent ());
Assign (In, Action.fifo);
Check (In, Exclude, eEnter, Action.pos);
ReleaseSet (In);
Difference (Action.fifo, Exclude);
}
Leaf (Id ())
DECLARE {
VAR In: tSet;
} {
MakeSet (In, MaxIdent ());
Assign (In, Leaf.fifo);
Check (In, Exclude, eEnter, Leaf.pos);
ReleaseSet (In);
Difference (Leaf.fifo, Exclude);
}
Alternative0 ()
{
Alternative0.depth := 0;
Difference (Alternative0.fifo, Exclude);
}
Alternative (expr, alternative)
DECLARE {
VAR E2: tSet;
} {
LL1 (expr, Exclude);
MakeSet (E2, MaxIdent ());
Assign (E2, Exclude);
Union (E2, expr.fifo);
LL1 (alternative, E2);
Alternative.depth := alternative.depth + 1;
ReleaseSet (E2);
Difference (Alternative.fifo, Exclude);
}
Sequence0 ()
DECLARE {
VAR In: tSet;
} {
MakeSet (In, MaxIdent ());
Assign (In, Sequence0.fifo);
Check (In, Exclude, eEnter, Sequence0.pos);
Difference (Sequence0.fifo, Exclude);
}
Sequence (expr, sequence)
{
LL1 (expr, Exclude);
IF IsEqual (expr.first, EpsilonSet) THEN
LL1 (sequence, Exclude);
ELSE
LL1 (sequence, EmptySet);
END;
Difference (Sequence.fifo, Exclude);
}
FUNCTION Recovery RecIn: tSet -> RecOut: tSet / rules, expr /
/*
* compute the recovery sets
*/
Rules0 ()
{}
Rules (Rule (Id (), codes, expr), rules)
{
Recovery (expr, RecIn, RecOut);
Recovery (rules, RecIn, RecOut);
}
Option (expr)
{
MakeSet (Option.recovery, MaxIdent ());
Assign (Option.recovery, RecIn);
Union (Option.recovery, Option.first);
Exclude (Option.recovery, Epsilon);
Recovery (expr, RecIn, RecOut);
Assign (RecOut, Option.recovery);
}
Times (expr)
{
MakeSet (Times.recovery, MaxIdent ());
Assign (Times.recovery, RecIn);
Union (Times.recovery, Times.first);
Exclude (Times.recovery, Epsilon);
Recovery (expr, RecIn, RecOut);
Assign (RecOut, Times.recovery);
}
Plus (expr)
{
MakeSet (Plus.recovery, MaxIdent ());
Assign (Plus.recovery, RecIn);
Union (Plus.recovery, Plus.first);
Exclude (Plus.recovery, Epsilon);
Recovery (expr, RecIn, RecOut);
Assign (RecOut, Plus.recovery);
}
List (body: expr, sep: expr)
DECLARE {
VAR In: tSet;
} {
MakeSet (List.recovery, MaxIdent ());
Assign (List.recovery, RecIn);
Union (List.recovery, body.first);
Union (List.recovery, sep.first);
Exclude (List.recovery, Epsilon);
MakeSet (In, MaxIdent ());
Assign (In, RecIn);
Union (In, sep.first);
Exclude (In, Epsilon);
Recovery (body, In, RecOut);
Assign (In, RecIn);
Union (In, body.first);
Exclude (In, Epsilon);
Recovery (sep, In, RecOut);
ReleaseSet (In);
Assign (RecOut, List.recovery);
}
Action (codes)
{
MakeSet (Action.recovery, MaxIdent ());
Assign (Action.recovery, RecIn);
Assign (RecOut, RecIn);
}
Leaf (Id ())
{
MakeSet (Leaf.recovery, MaxIdent ());
Assign (RecOut, RecIn);
Union (RecOut, Leaf.first);
Exclude (RecOut, Epsilon);
IF IsTerm (Id.ident) THEN
Assign (Leaf.recovery, RecOut);
ELSE
Assign (Leaf.recovery, RecIn);
END;
}
Alternative0 ()
{
ERROR ('Sem.estra: Alternative0 unexpected');
}
Alternative (:expr, :alternative)
DECLARE {
VAR RecUnion: tSet;
} {
MakeSet (RecUnion, MaxIdent ());
Assign (RecUnion, RecIn);
RecoveryAlt (Alternative, RecIn, RecUnion, RecOut);
ReleaseSet (RecUnion);
}
Sequence0 ()
{
MakeSet (Sequence0.recovery, MaxIdent ());
Assign (Sequence0.recovery, RecIn);
Assign (RecOut, RecIn);
}
Sequence (expr, sequence)
{
MakeSet (Sequence.recovery, MaxIdent ());
Recovery (sequence, RecIn, RecOut);
Recovery (expr, RecOut, Sequence.recovery);
Assign (RecOut, Sequence.recovery);
}
FUNCTION RecoveryAlt RecIn: tSet; RecUnion: tSet -> RecOut: tSet
/ alternative /
/*
* compute the recovery sets (alternative)
*/
Alternative0 ()
{
MakeSet (Alternative0.recovery, MaxIdent ());
Exclude (RecUnion, Epsilon);
Assign (Alternative0.recovery, RecUnion);
Assign (RecOut, RecUnion);
}
Alternative (expr, alternative)
{
MakeSet (Alternative.recovery, MaxIdent ());
Recovery (expr, RecIn, RecOut);
Union (RecUnion, expr.first);
RecoveryAlt (alternative, RecIn, RecUnion, RecOut);
Assign (Alternative.recovery, RecOut);
}
FUNCTION PrepareCode PossibleTerms: tSet -> IsCalling: BOOLEAN / rules, expr /
/*
* prepare the code generation
*/
Rules0 ()
{}
Rules (Rule (Id (), codes, expr), rules)
{
PrepareCode (expr, PossibleTerms, Rule.iscalling);
PrepareCode (rules, PossibleTerms, IsCalling);
}
Option (expr)
{
Option.index := Index (Option.first);
Option.followindex := Index (Option.follow);
Option.expindex := ExpIndex (Option.first, Option.follow, Option.recovery);
Option.recindex := RecSetIndex (Option.recovery);
PrepareCode (expr, expr.fifo, IsCalling);
}
Times (expr)
{
Times.index := Index (Times.first);
Times.followindex := Index (Times.follow);
Times.expindex := ExpIndex (Times.first, Times.follow, Times.recovery);
Times.recindex := RecSetIndex (Times.recovery);
PrepareCode (expr, expr.fifo, IsCalling);
}
Plus (expr)
DECLARE {
VAR set: tSet;
} {
Plus.index := Index (Plus.first);
Plus.followindex := Index (Plus.follow);
Plus.expindex := ExpIndex (Plus.first, Plus.follow, Plus.recovery);
Plus.recindex := RecSetIndex (Plus.recovery);
MakeSet (set, MaxIdent ());
Assign (set, PossibleTerms);
Union (set, expr.fifo);
PrepareCode (expr, set, IsCalling);
ReleaseSet (set);
}
List (body: expr, sep: expr)
DECLARE {
VAR iscalling: BOOLEAN;
} {
List.index := Index (List.first);
List.followindex := Index (List.follow);
List.expindex := ExpIndex (sep.first, List.follow, List.recovery);
List.recindex := RecSetIndex (List.recovery);
PrepareCode (body, AnySymbol, iscalling);
PrepareCode (sep, AnySymbol, IsCalling);
IsCalling := IsCalling OR iscalling;
}
Action (codes) { IsCalling := FALSE; }
Leaf (Id ())
{
Leaf.sure := IsSubset (PossibleTerms, Leaf.fifo);
IF Leaf.sure OR IsNonterm (Id.ident) THEN
Leaf.index := cNoIndex;
ELSE
Leaf.index := Index (Leaf.first);
END;
Leaf.recindex := RecSetIndex (Leaf.recovery);
(* Leaf.followindex := Index (Leaf.follow); *)
IsCalling := IsNonterm (Id.ident);
}
Alternative0 ()
{
ERROR ('Sem.estra: Alternative0 unexpected');
}
Alternative (:expr, :alternative)
DECLARE {
VAR case: BOOLEAN; maxdepth: INTEGER;
} {
maxdepth := MaxDepth;
IF IsSubset (PossibleTerms, Alternative.fifo) (* OR IsElement (Epsilon, Alternative.first) *) THEN
INC (maxdepth);
END;
case := Alternative.depth > maxdepth;
PrepareCodeAlt (Alternative, case, PossibleTerms, Alternative.first, NoTree, IsCalling);
}
Sequence0 () { IsCalling := FALSE; }
Sequence (expr, sequence)
DECLARE {
VAR iscalling: BOOLEAN;
} {
PrepareCode (expr, PossibleTerms, iscalling);
IF IsElement (Epsilon, expr.first) & (Card (expr.first) = 1) THEN
PrepareCode (sequence, PossibleTerms, IsCalling);
ELSE
PrepareCode (sequence, AnySymbol, IsCalling);
END;
IsCalling := IsCalling OR iscalling;
}
FUNCTION PrepareCodeAlt Case: BOOLEAN;
PossibleTerms: tSet;
First: tSet;
Default: tTree -> IsCalling: BOOLEAN / alternative /
/*
* prepare the code generation (alternative)
*/
Alternative0 ()
DECLARE {
VAR LocalFollow: tSet;
} {
MakeSet (LocalFollow, MaxIdent ());
Assign (LocalFollow, Alternative0.follow);
Intersection (LocalFollow, Alternative0.recovery);
IF NOT IsEmpty (LocalFollow) OR NOT IsElement (Epsilon, First) THEN
Union (LocalFollow, First);
Exclude (LocalFollow, Epsilon);
Alternative0.expindex := RecSetIndex (LocalFollow);
ELSE
Alternative0.expindex := cNoIndex;
END;
ReleaseSet (LocalFollow);
Alternative0.case := Case;
Alternative0.default := Default;
Alternative0.recindex := RecSetIndex (Alternative0.recovery);
(* Alternative0.followindex := Index (Alternative0.follow); *)
IsCalling := FALSE;
}
Alternative (e1:expr, alternative)
DECLARE {
VAR possible: tSet; iscalling: BOOLEAN;
} {
Alternative.case := Case;
PrepareCode (e1, e1.fifo, iscalling);
MakeSet (possible, MaxIdent ());
Assign (possible, PossibleTerms);
IF (Default = NoTree) OR (Default^.expr.length > e1.length) THEN
Default := e1;
END;
Difference (possible, e1.fifo);
IF NOT Case THEN
Alternative.index := Index (e1.fifo);
END;
(* Alternative.followindex := Index (Alternative.follow); *)
PrepareCodeAlt (alternative, Case, possible, First, Default, IsCalling);
IsCalling := IsCalling OR iscalling;
ReleaseSet (possible);
}